local skynet = require "skynet"
local socket = require "skynet.socket"
local packet = require "packet"
local redis = require "redisutil"

local tunpack = table.unpack
local tconcat = table.concat
local select = select

local hall

local CMD = {}
local MSG = {}
local clients = {}

local function client_quit(clientfd)
    if not clients[clientfd] then
        return
    end
    local client = clients[clientfd]
    skynet.call(hall, "lua", "offline", client.name)
    if client.isgame and client.isgame > 0 then
        skynet.call(client.isgame, "lua", "offline", client.name)
    end
    clients[clientfd] = nil
    socket.close(clientfd)
end

function MSG.ready(clientfd)
    local client = assert(clients[clientfd])
    if not client.name then
        packet.send_packet(clientfd, "请先登陆")
        return
    end
    if client.isgame and client.isgame > 0 then
        packet.send_packet(clientfd, "在游戏中，不能准备")
        return
    end
    local ok, msg = skynet.call(hall, "lua", "ready", client)
    if not ok then
        packet.send_packet(clientfd, msg)
        return
    end
    client.isgame = ok
    redis:hset("role:"..client.name, "isgame", ok)
end

function MSG.guess(clientfd, number)
    local client = assert(clients[clientfd])
    if not client.name then
        packet.send_packet(clientfd, "错误：请先登陆")
        return
    end
    if not client.isgame or client.isgame == 0 then
        packet.send_packet(clientfd, "错误：没有在游戏中，请先准备")
        return
    end
    local numb = math.tointeger(number)
    if not numb then
        packet.send_packet(clientfd, "错误：猜测时需要提供一个整数而不是 "..number)
        return
    end

    skynet.send(client.isgame, "lua", "guess", client.name, numb)
end

function MSG.help(clientfd)
    local params = tconcat({
        "*规则*:猜数字游戏，由系统随机1-100数字，猜中输，未猜中赢。",
        "help: 显示所有可输入的命令;",
        "login: 登陆，需要输入用户名和密码;",
        "ready: 准备，加入游戏队列，满员自动开始游戏;",
        "guess: 猜数字，只能猜1~100之间的数字;",
        "quit: 退出",
    }, "\n")
    packet.send_packet(clientfd, params)
end

function MSG.quit(clientfd)
    client_quit(clientfd)
end

local function process_socket_events(clientfd)
    while true do
        local data = packet.recv_packet(clientfd)
        if not data then
            print("断开网络 "..clientfd)
            client_quit(clientfd)
            return
        end
        if not next(data) then
            packet.send_packet(clientfd, "recv an empty packet")
            goto __continue__
        end
        local cmd = data[1]
        if not MSG[cmd] then
            packet.send_packet(clientfd, cmd.." 该命令不存在")
            MSG.help(clientfd)
            goto __continue__
        end
        skynet.fork(MSG[cmd], clientfd, select(2, tunpack(data)))
::__continue__::
    end
end

function CMD.game_over(clientfd)
    local client = assert(clients[clientfd])
    client.isgame = 0
    redis:hset("role:"..client.name, "isgame", 0)
end

function CMD.start(client)
    local clientfd = assert(client.fd)
    client.agent = skynet.self()
    clients[clientfd] = client
    socket.start(clientfd)
    skynet.fork(process_socket_events, clientfd)
    skynet.retpack()
end

skynet.start(function ()
    redis:init(skynet.uniqueservice("redis"))
    hall = skynet.uniqueservice("hall")
    skynet.dispatch("lua", function (_, _, cmd, ...)
        local func = assert(CMD[cmd])
        func(...)
    end)
end)
